﻿using BeetleX.Buffers;
using Newtonsoft.Json;
using System;
using System.Buffers;
using System.IO;
using System.Text;

#nullable disable
namespace BeetleX.XRPC.Packets
{
    public class JsonPacket : IParameterFormater
    {
        private readonly JsonConverter[] Converters = new JsonConverter[1] { new StreamJsonConverter() };

        public object Decode(Options rpcOption, Type type, ArraySegment<byte> data)
        {
            int count = data.Count;
            if (count == 0)
                return type.IsValueType ? Activator.CreateInstance(type) : (object)null;
            if (type != null)
                return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data.Array, data.Offset, data.Count), type, Converters);
            byte[] numArray = ArrayPool<byte>.Shared.Rent(count);
            System.Buffer.BlockCopy(data.Array, data.Offset, numArray, 0, data.Count);
            return new ArraySegment<byte>(numArray, 0, count);
        }

        public void Encode(Options rpcOption, object data, PipeStream stream)
        {
            if (data == null)
            {
                stream.Write(0);
            }
            else
            {
                MemoryBlockCollection memoryBlockCollection = stream.Allocate(4);
                int cacheLength = stream.CacheLength;
                string str = JsonConvert.SerializeObject(data, Converters);
                stream.Write(str);
                memoryBlockCollection.Full(stream.CacheLength - cacheLength);
            }
        }
    }

    public class StreamJsonConverter : Newtonsoft.Json.JsonConverter<Stream>
    {
        public override Stream ReadJson(JsonReader reader, Type objectType, Stream existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            Stream stream = null;
            string base64Str = reader.Value as string;
            if (!string.IsNullOrEmpty(base64Str))
            {
                byte[] buffer = ArrayPool<byte>.Shared.Rent(base64Str.Length * 2);
                if (Convert.TryFromBase64String(base64Str, buffer, out int writeNum) && writeNum > 0)
                {
                    stream = new MemoryStream(buffer, 0, writeNum);
                }
                ArrayPool<byte>.Shared.Return(buffer);
            }
            return stream;
        }

        public override void WriteJson(JsonWriter writer, Stream value, JsonSerializer serializer)
        {
            if (value != null && value.CanRead && value.Length > 0)
            {
                int realLen = (int)(value.Length - value.Position);
                if (realLen > 0)
                {
                    byte[] buffer = ArrayPool<byte>.Shared.Rent(realLen);
                    int readNum = value.Read(buffer);
                    writer.WriteValue(Convert.ToBase64String(buffer, 0, readNum));
                    ArrayPool<byte>.Shared.Return(buffer);
                }
            }
        }
    }

}